/*
 * Copyright (C) 2004 NNL Technology AB
 * Visit www.infonode.net for information about InfoNode(R) 
 * products and how to contact NNL Technology AB.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, 
 * MA 02111-1307, USA.
 */

// $Id: ShapedGradientTheme.java,v 1.14 2005/12/04 13:46:05 jesper Exp $
package net.infonode.tabbedpanel.theme;

import net.infonode.gui.HighlightPainter;
import net.infonode.gui.InsetsUtil;
import net.infonode.gui.colorprovider.*;
import net.infonode.gui.componentpainter.GradientComponentPainter;
import net.infonode.tabbedpanel.Tab;
import net.infonode.tabbedpanel.TabbedPanelProperties;
import net.infonode.tabbedpanel.TabbedUtils;
import net.infonode.tabbedpanel.border.OpenContentBorder;
import net.infonode.tabbedpanel.internal.SlopedTabLineBorder;
import net.infonode.tabbedpanel.titledtab.TitledTabBorderSizePolicy;
import net.infonode.tabbedpanel.titledtab.TitledTabProperties;
import net.infonode.tabbedpanel.titledtab.TitledTabStateProperties;

import javax.swing.border.Border;

import java.awt.*;

/**
 * A theme with tabs with rounded edges, gradient backgrounds and support for slopes on left/right side of tab.
 *
 * @author $Author: jesper $
 * @version $Revision: 1.14 $
 * @since ITP 1.2.0
 */
public class ShapedGradientTheme extends TabbedPanelTitledTabTheme {
	private static final int CORNER_INSET = 3;

	private ColorProvider highlightColor;
	private ColorProvider lineColor;
	private ColorProvider controlColor;
	private ColorProvider darkControlColor;
	private ColorProvider alternateHighlight;
	private int leftSlopeHeight;
	private int rightSlopeHeight;

	private static class TabBorder extends SlopedTabLineBorder {
		private boolean bottomLeftRounded;
		private boolean isNormal;
		private boolean hasLeftSlope;
		private int raised;
		private int cornerInset;

		TabBorder(ColorProvider lineColor, ColorProvider highlightColor, float leftSlope, float rightSlope, int leftHeight, int rightHeight,
				boolean bottomLeftRounded, boolean topLeftRounded, boolean topRightRounded, boolean bottomRightRounded, boolean isNormal,
				boolean highlightBottomLeftRounded, int raised) {
			super(lineColor, highlightColor, false, leftSlope, rightSlope, leftHeight, rightHeight, isNormal ? false : bottomLeftRounded, topLeftRounded,
					topRightRounded, bottomRightRounded);

			this.bottomLeftRounded = bottomLeftRounded;
			this.isNormal = isNormal;
			this.raised = raised;
			hasLeftSlope = leftSlope > 0;

			cornerInset = highlightBottomLeftRounded ? CORNER_INSET : 0;
		}

		@Override
		protected Polygon createPolygon(Component c, int width, int height) {
			Polygon p = super.createPolygon(c, width, height);
			if (isNormal) {
				int leftX = width / 2;
				boolean first = isFirst(c);
				for (int i = 0; i < p.npoints; i++) {
					if (p.xpoints[i] < leftX)
						p.xpoints[i] = p.xpoints[i] + raised + (first ? 0 : cornerInset);
					else
						p.xpoints[i] = p.xpoints[i] - raised - cornerInset;
				}
			}

			return p;
		}

		@Override
		protected Insets getShapedBorderInsets(Component c) {
			Insets i = super.getShapedBorderInsets(c);

			Insets addInsets = new Insets(0, 0, 0, 1 + raised);
			if (isNormal && !isFirst(c))
				addInsets.left = addInsets.left + cornerInset;
			if (!isNormal)
				addInsets.right = addInsets.right - cornerInset;

			return InsetsUtil.add(i, addInsets);
		}

		private boolean isFirst(Component c) {
			if (!hasLeftSlope) {
				Tab tab = TabbedUtils.getParentTab(c);
				if (tab != null && tab.getTabbedPanel() != null) {
					return tab.getTabbedPanel().getTabAt(0) == tab;
				}
			}

			return false;
		}

		@Override
		protected boolean isBottomLeftRounded(Component c) {
			return isFirst(c) ? false : bottomLeftRounded;
		}
	}

	private TabbedPanelProperties tabbedPanelProperties = new TabbedPanelProperties();
	private TitledTabProperties titledTabProperties = new TitledTabProperties();

	/**
	 * Creates a default theme with sloped border on the right side of the tab and with colors based on the active look and feel
	 */
	public ShapedGradientTheme() {
		this(0f, 0.5f);
	}

	/**
	 * Creates a theme with the given slopes on the left and right side of the tab and with colors based on the active look and feel
	 *
	 * @param leftSlope leaning of left slope defined as left slope width divided by left slope height
	 * @param rightSlope leaning of right slope defined as right slope width divided by right slope height
	 */
	public ShapedGradientTheme(float leftSlope, float rightSlope) {
		this(leftSlope, rightSlope, UIManagerColorProvider.TABBED_PANE_DARK_SHADOW, UIManagerColorProvider.TABBED_PANE_HIGHLIGHT);
	}

	/**
	 * Creates a theme with the given slopes on the left and right side of the tab and with the given colors
	 *
	 * @param leftSlope leaning of left slope defined as left slope width divided by left slope height
	 * @param rightSlope leaning of right slope defined as right slope width divided by right slope height
	 * @param lineColor color provider for the lines
	 * @param highlightColor color provider for the highlighting, null for no highlighting
	 */
	public ShapedGradientTheme(float leftSlope, float rightSlope, ColorProvider lineColor, ColorProvider highlightColor) {
		this(leftSlope, rightSlope, 25, lineColor, highlightColor);
	}

	/**
	 * Creates a theme with the given slopes on the left and right side of the tab and with the given colors
	 *
	 * @param leftSlope leaning of left slope defined as left slope width divided by left slope height
	 * @param rightSlope leaning of right slope defined as right slope width divided by right slope height
	 * @param slopeHeight slope height in pixels, used when estimating slope width
	 * @param lineColor color provider for the lines
	 * @param highlightColor color provider for the highlighting, null for no highlighting
	 */
	public ShapedGradientTheme(float leftSlope, float rightSlope, int slopeHeight, ColorProvider lineColor, ColorProvider highlightColor) {
		this.leftSlopeHeight = slopeHeight;
		this.rightSlopeHeight = slopeHeight;
		this.highlightColor = highlightColor;
		this.lineColor = lineColor;
		this.controlColor = UIManagerColorProvider.CONTROL_COLOR;
		darkControlColor = UIManagerColorProvider.TABBED_PANE_BACKGROUND;
		alternateHighlight = highlightColor != null ? new ColorBlender(highlightColor, controlColor, 0.3f) : (ColorProvider) new ColorMultiplier(controlColor,
				1.2);

		GradientComponentPainter blendedComponentPainter = new GradientComponentPainter(alternateHighlight, alternateHighlight, controlColor, controlColor);

		int leftSlopeWidth = (int) (leftSlope * leftSlopeHeight);
		int rightSlopeWidth = (int) (rightSlope * rightSlopeHeight);
		int highlightedRaised = 2;

		boolean bottomLeftRounded = true;
		boolean topLeftRounded = true;
		boolean topRightRounded = true;
		boolean bottomRightRounded = true;

		titledTabProperties.setHighlightedRaised(highlightedRaised).setBorderSizePolicy(TitledTabBorderSizePolicy.EQUAL_SIZE);

		TitledTabStateProperties normalState = titledTabProperties.getNormalProperties();
		TitledTabStateProperties highlightState = titledTabProperties.getHighlightedProperties();
		TitledTabStateProperties disabledState = titledTabProperties.getDisabledProperties();

		Border normalBorder = new TabBorder(lineColor, null, leftSlope, rightSlope, leftSlopeHeight, rightSlopeHeight, false, topLeftRounded, topRightRounded,
				false, true, true, highlightedRaised);
		Border highlightBorder = new TabBorder(lineColor, highlightColor, leftSlope, rightSlope, leftSlopeHeight, rightSlopeHeight, bottomLeftRounded,
				topLeftRounded, topRightRounded, bottomRightRounded, false, true, highlightedRaised);

		normalState.getComponentProperties().setBorder(normalBorder).setInsets(new Insets(0, 0, 0, 0));
		highlightState.getComponentProperties().setBorder(highlightBorder);

		ColorProvider darkControlColor1 = new ColorMultiplier(darkControlColor, 1.1);
		ColorProvider darkControlColor2 = new ColorMultiplier(darkControlColor, 0.92);
		GradientComponentPainter normalComponentPainter = new GradientComponentPainter(darkControlColor1, darkControlColor1, darkControlColor2,
				darkControlColor2);
		normalState.getShapedPanelProperties().setOpaque(false).setComponentPainter(normalComponentPainter);
		disabledState.getShapedPanelProperties().setComponentPainter(normalComponentPainter);

		if (highlightColor == null)
			highlightState.getShapedPanelProperties().setComponentPainter(blendedComponentPainter);
		else
			highlightState.getShapedPanelProperties().setComponentPainter(
					new GradientComponentPainter(highlightColor, highlightColor, controlColor, controlColor));

		Insets insets = normalBorder.getBorderInsets(null);
		int tabSpacing = 1 + insets.left + insets.right - (topLeftRounded ? CORNER_INSET : 0) - (topRightRounded ? CORNER_INSET : 0)
				- (int) (0.2 * (leftSlopeWidth + rightSlopeWidth));
		tabbedPanelProperties.setTabSpacing(-tabSpacing).setShadowEnabled(false);

		tabbedPanelProperties.getTabAreaComponentsProperties().getComponentProperties()
				.setBorder(new SlopedTabLineBorder(lineColor, highlightColor, false, 0f, 0f, 0, 0, false, topLeftRounded, topRightRounded, false))
				.setInsets(new Insets(0, 0, 0, 0));

		tabbedPanelProperties.getTabAreaComponentsProperties().getShapedPanelProperties().setComponentPainter(blendedComponentPainter);

		tabbedPanelProperties.getTabAreaProperties().getShapedPanelProperties().setOpaque(false);

		tabbedPanelProperties
				.getContentPanelProperties()
				.getComponentProperties()
				.setBorder(
						new OpenContentBorder(lineColor, lineColor, highlightColor == null ? null : new ColorBlender(highlightColor,
								BackgroundPainterColorProvider.INSTANCE, HighlightPainter.getBlendFactor(1, 0)), 1));
	}

	/**
	 * Gets the theme name
	 *
	 * @return name for this theme
	 */
	@Override
	public String getName() {
		return "Shaped Gradient Theme";
	}

	/**
	 * Gets the TabbedPanelProperties for this theme
	 *
	 * @return the TabbedPanelProperties
	 */
	@Override
	public TabbedPanelProperties getTabbedPanelProperties() {
		return tabbedPanelProperties;
	}

	/**
	 * Gets the TitledTabProperties for this theme
	 *
	 * @return the TitledTabProperties
	 */
	@Override
	public TitledTabProperties getTitledTabProperties() {
		return titledTabProperties;
	}

	/**
	 * Gets the line color provider
	 *
	 * @return the line color provider
	 */
	public ColorProvider getLineColor() {
		return lineColor;
	}

	/**
	 * Gets the highlight color provider
	 *
	 * @return the highlight color provider, null if no highlight
	 */
	public ColorProvider getHighlightColor() {
		return highlightColor;
	}

	/**
	 * Gets the alternate highlight color provider used for tab area components gradient background and highlighted tab background (when no highlight color is
	 * specified)
	 *
	 * @return the alternate highlight color provider
	 */
	public ColorProvider getAlternateHighlightColor() {
		return alternateHighlight;
	}

	/**
	 * Gets the control background color
	 *
	 * @return the control background color provider
	 */
	public ColorProvider getControlColor() {
		return controlColor;
	}

	/**
	 * Gets the dark control background color used for gradient for normal tab and disabled tab
	 *
	 * @return the dark control background color provider
	 */
	public ColorProvider getDarkControlColor() {
		return darkControlColor;
	}

	/**
	 * Creates a tab border
	 *
	 * @param lineColor line color provider
	 * @param highlightColor highlight color provider, null for no highlight
	 * @param leftSlope left slope
	 * @param rightSlope right slope
	 * @param bottomLeftRounded true if bottom left should be rounded
	 * @param topLeftRounded true if top left should be rounded
	 * @param topRightRounded true if top right should be rounded
	 * @param bottomRightRounded true if bottom right should be rounded
	 * @param isNormal true if this is a normal rendered border
	 * @param highlightBottomLeftRounded true if highlight has bottom left rounded
	 * @param raised raised
	 * @return the created border
	 */
	public Border createTabBorder(ColorProvider lineColor, ColorProvider highlightColor, float leftSlope, float rightSlope, boolean bottomLeftRounded,
			boolean topLeftRounded, boolean topRightRounded, boolean bottomRightRounded, boolean isNormal, boolean highlightBottomLeftRounded, int raised) {
		return new TabBorder(lineColor, highlightColor, leftSlope, rightSlope, 25, 25, bottomLeftRounded, topLeftRounded, topRightRounded, bottomRightRounded,
				isNormal, highlightBottomLeftRounded, raised);
	}
}